﻿// //  ********************************************************************************
// //  Copyright (C) 2016 Sebastian Kenter. All rights reserved.
// // 
// //  Name    : PhotonServerProject | PhotonServerFramework | ServerHandlerRegistry.cs
// //  Created : 2016 - 03 - 22 16:01
// //  Modified: 2016 - 04 - 18 09:38
// //  ********************************************************************************

using System;
using System.Collections.Generic;
using System.Linq;
using ExitGames.Logging;
using NHibernate;
using PhotonServerCommon.Entities.Domain;
using PhotonServerCommon.Enums;
using PhotonServerFramework.Implementation.Database;
using PhotonServerFramework.Interfaces.Application;
using PhotonServerFramework.Interfaces.Handler;
using PhotonServerFramework.Interfaces.Server;

namespace PhotonServerFramework.Implementation.Handler
{
    public class ServerHandlerRegistry : IServerHandlerRegistry
    {
        public ILogger Logger { get; }

        private readonly Dictionary<Guid, IServerTelegramHandler<IServerPeer>> _serverTelegramHandlers =
            new Dictionary<Guid, IServerTelegramHandler<IServerPeer>>();

        public ServerHandlerRegistry(ILogger logger)
        {
            Logger = logger;
        }

        public bool RegisterServerHandler(IServerTelegramHandler<IServerPeer> serverHandler, IServerApplication server)
        {
            bool registered = false;

            Logger.InfoFormat("Received register request for handler: {0} (type={1}, code={2}, subcode={3})",
                serverHandler.GetType().Name,
                serverHandler.HandlerType, (OperationCodes) serverHandler.HandlerCode,
                (OperationSubCodes) serverHandler.HandlerSubCode);

            if (!_serverTelegramHandlers.ContainsKey(serverHandler.HandlerId))
            {
                _serverTelegramHandlers.Add(serverHandler.HandlerId, serverHandler);

                HandlerT handler = new HandlerT
                                   {
                                       Application = server.Configuration.Application,
                                       HandlerType = (int) serverHandler.HandlerType,
                                       HandlerCode = serverHandler.HandlerCode,
                                       HandlerSubCode = serverHandler.HandlerSubCode,
                                       HandlerId = serverHandler.HandlerId.ToString(),
                                       ClientHandler = 0,
                                       ServerHandler = 1,
                                       ServerId = server.ServerId.ToString(),
                                       ServerPeerId = "",
                                       DzIns = DateTime.Now,
                                       DzUpd = DateTime.Now,
                                       NamUpd = GetType().Name,
                                       Tsn = 1
                                   };
                using (ISession session = SessionManager.OpenSession())
                {
                    using (ITransaction transaction = session.BeginTransaction())
                    {
                        try
                        {
                            session.Save(handler);
                            transaction.Commit();
                            registered = true;
                        }
                        catch (Exception ex)
                        {
                            Logger.ErrorFormat("Operation failed with: {0}", ex.Message);
                            transaction.Rollback();
                        }
                    }
                    session.Close();
                }
            }
            else
            {
                Logger.ErrorFormat("Cannot register handler with id {0} - already exists in registry.",
                    serverHandler.HandlerId);
            }

            if (registered)
            {
                Logger.InfoFormat("Handler with id {0} successfully registered internally and with database.",
                    serverHandler.HandlerId);
            }
            else
            {
                Logger.ErrorFormat("Handler with id {0} cannot be registered internally and with database",
                    serverHandler.HandlerId);
            }

            return registered;
        }

        public bool UnregisterServerHandler(Guid handlerId)
        {
            bool unregistered = false;

            Logger.InfoFormat("Received unregister request for handler id={0}", handlerId);

            if (_serverTelegramHandlers.ContainsKey(handlerId))
            {
                _serverTelegramHandlers.Remove(handlerId);

                using (ISession session = SessionManager.OpenSession())
                {
                    using (ITransaction transaction = session.BeginTransaction())
                    {
                        try
                        {
                            HandlerT handler =
                                session.QueryOver<HandlerT>()
                                    .Where(h => h.HandlerId == handlerId.ToString())
                                    .SingleOrDefault();
                            session.Delete(handler);
                            transaction.Commit();
                            unregistered = true;
                        }
                        catch (Exception ex)
                        {
                            Logger.ErrorFormat("Operation failed with: {0}", ex.Message);
                            transaction.Rollback();
                        }
                    }
                    session.Close();
                }
            }
            else
            {
                Logger.ErrorFormat("Cannot unregister handler with id {0} - does not exists in registry.", handlerId);
            }

            if (unregistered)
            {
                Logger.InfoFormat("Handler with id {0} successfully unregistered internally and with database.",
                    handlerId);
            }
            else
            {
                Logger.ErrorFormat("Handler with id {0} cannot be unregistered internally and with database", handlerId);
            }

            return unregistered;
        }

        public IServerTelegramHandler<IServerPeer> GetServerHandlerById(Guid handlerId)
        {
            return _serverTelegramHandlers.FirstOrDefault(h => h.Key == handlerId).Value;
        }
    }
}
